package com.feituan.wx.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.feituan.core.exception.BusinessException;
import com.feituan.core.exception.RequestInvalidException;
import com.feituan.core.persistence.service.IMerchantService;
import com.feituan.core.persistence.service.IOrderService;
import com.feituan.core.persistence.service.IProductService;
import com.feituan.core.persistence.service.IUserService;
import com.feituan.core.pojo.entity.Merchant;
import com.feituan.core.pojo.entity.Order;
import com.feituan.core.pojo.entity.Product;
import com.feituan.core.pojo.entity.User;
import com.feituan.core.pojo.request.PrinterRequest;
import com.feituan.core.pojo.response.Response;
import com.feituan.core.service.IPrinterService;
import com.feituan.core.util.PrinterTemplate;
import com.feituan.wx.request.GoodReq;
import com.feituan.wx.request.OrderListReq;
import com.feituan.wx.request.SubmitOrderReq;
import com.feituan.wx.service.OrderService;
import com.feituan.wx.vo.OrderGoodVo;
import com.feituan.wx.vo.OrderVo;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Response;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author xiaohu
 * @since 2024-05-09
 */
@RestController
@RequestMapping("/order")
@Api(tags = "订单管理")
public class OrderController extends BaseController {
    private final static Logger logger = LoggerFactory.getLogger(OrderController.class);
    @Autowired
    private OrderService orderService;
    @Autowired
    private IUserService iUserService;

    @Autowired
    private IOrderService iOrderService;
    @Autowired
    private IProductService iProductService;
    @Autowired
    private IMerchantService iMerchantService;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private IPrinterService iPrinterService;

    @Autowired
    private PrinterTemplate printerTemplate;

    @PostMapping("/submit")
    @ApiOperation("提交订单")
    public Response<Map<String, String>> submitOrder(@RequestBody SubmitOrderReq req) {
        if (req.getUserId() == null || req.getMerchantId() == null || CollectionUtils.isEmpty(req.getProducts())) {
            throw new RequestInvalidException();
        }
        User user = iUserService.getById(req.getUserId());
        if (user == null) {
            throw new RequestInvalidException();
        }
        Merchant merchant = iMerchantService.getById(req.getMerchantId());
        if (merchant == null) {
            throw new RequestInvalidException();
        }
        List<Long> productIds = req.getProducts().stream().map(GoodReq::getId).distinct().collect(Collectors.toList());
        List<Product> products = iProductService.lambdaQuery().in(Product::getId, productIds).list();
        if (CollectionUtils.isEmpty(products) || products.size() != productIds.size()) {
            throw new RequestInvalidException();
        }
        String sn = orderService.submit(req, user, merchant,products);
        Map<String, String> map = new HashMap<>();
        map.put("sn", sn);
        map.put("payType", req.getPayType().toString());
        List<PrinterRequest> printerRequests = printerTemplate.templateEquipment(sn);
        iPrinterService.printer(printerRequests);
        return Response.success(map);
    }


    /**
     * 余额支付
     * @param orderSn orderSn
     * @return
     */
    @PostMapping("/balancePay")
    public Response<String> balancePayment(String orderSn) {
        return Response.success(orderService.balancePayment(orderSn));
    }


    @PostMapping("/prepay")
    @ApiOperation("预支付")
    public Response<WxPayUnifiedOrderV3Result.JsapiResult> prepay(HttpServletRequest request, String orderSn) {
        if (StringUtils.isEmpty(orderSn)) {
            throw new RequestInvalidException();
        }
        Order order = iOrderService.getBySn(orderSn);
        if (order == null) {
            throw new RequestInvalidException();
        }
        WxPayUnifiedOrderV3Result.JsapiResult result = orderService.prepay(order, request);
        return Response.success(result);
    }

    @PostMapping("pay_notify")
    public String payNotify(@RequestBody String notifyData, HttpServletRequest request) {
        logger.info("pay notify start param :{}", notifyData);
        WxPayNotifyV3Result result = null;
        try {
            result = this.wxPayService.parseOrderNotifyV3Result(notifyData, this.getRequestHeader(request));
        } catch (WxPayException e) {
            return WxPayNotifyV3Response.fail("fail");
        }
        // 解密后的数据
        WxPayNotifyV3Result.DecryptNotifyResult notifyResult = result.getResult();
        logger.info("pay notify parsed param：{}", JSONObject.toJSONString(notifyResult));
        if (WxPayConstants.WxpayTradeStatus.PAY_ERROR.equals(notifyResult.getTradeState())) {
            logger.error("【pay notify error:{}", result);
            return WxPayNotifyV3Response.fail("fail");
        }
        if (WxPayConstants.WxpayTradeStatus.SUCCESS.equals(notifyResult.getTradeState())) {
            try {
                orderService.dtsPayNotify(notifyResult);
            } catch (BusinessException e) {
                return WxPayNotifyV3Response.fail("fail");
            } catch (Exception e) {
                logger.info("pay notify error :{}", e);
                return WxPayNotifyV3Response.fail("fail");
            }
        }

        logger.info("pay notify complete");
        return WxPayNotifyV3Response.success("ok");
    }

    /**
     * 获取回调请求头：签名相关
     *
     * @param request HttpServletRequest
     * @return SignatureHeader
     */
    public SignatureHeader getRequestHeader(HttpServletRequest request) {
        // 获取通知签名
        String signature = request.getHeader("Wechatpay-Signature");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String serial = request.getHeader("Wechatpay-Serial");
        String timestamp = request.getHeader("Wechatpay-Timestamp");

        SignatureHeader signatureHeader = new SignatureHeader();
        signatureHeader.setSignature(signature);
        signatureHeader.setNonce(nonce);
        signatureHeader.setSerial(serial);
        signatureHeader.setTimeStamp(timestamp);
        return signatureHeader;
    }

    @PostMapping("/detail")
    @ApiOperation("订单详情")
    public Response<OrderVo> detail(String orderSn) {
        Order order = iOrderService.getBySn(orderSn);
        if (order == null) {
            throw new RequestInvalidException();
        }
        OrderVo orderVo = new OrderVo();
        BeanUtils.copyProperties(order, orderVo);
        orderVo.setProductVos(JSON.parseArray(order.getProducts(), OrderGoodVo.class));
        return Response.success(orderVo);
    }

    @PostMapping("/list")
    @ApiOperation("我的订单")
    public Response<List<OrderVo>> list(OrderListReq req) {
        if (req.getUserId() == null) {
            throw new RequestInvalidException();
        }
        List<OrderVo> orderVos = new ArrayList<>();
        List<Order> orders = iOrderService.findByUser(req.getUserId(),req.getType(), req.getLastId(), req.getOrderStatus());
        if (!CollectionUtils.isEmpty(orders)) {
            for (Order order : orders) {
                OrderVo orderVo = new OrderVo();
                BeanUtils.copyProperties(order, orderVo);
                orderVo.setProductVos(JSON.parseArray(order.getProducts(), OrderGoodVo.class));
                orderVos.add(orderVo);
            }
        }
        return Response.success(orderVos);
    }



}
